/****************************************************
	文件：SchemeToolsEditor.cs
	作者：HuskyT
	邮箱：1005240602@qq.com
	日期：2020/9/20 10:59:26
	功能：配置表转换器
*****************************************************/

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Text;
using HTFW.Consts;
using HTFW.Utility.Runtime;
using HTFW.Utility.Editor;

namespace HTFW.Scheme
{
    public class SchemeToolsEditor : EditorWindow
    {
        /// <summary>
        /// 窗口实例
        /// </summary>
        private static EditorWindow mWnd;

        /// <summary>
        /// Excel文件路径列表
        /// </summary>
        private static List<string> mExcelPathList;

        /// <summary>
        /// 项目路径
        /// </summary>
        private static string mRootPath;

        /// <summary>
        /// 滚动窗口初始位置
        /// </summary>
        private static Vector2 mScrollPos;

        /// <summary>
        /// 是否生成C#
        /// </summary>
        private static bool mGenerateCSharp;

        /// <summary>
        /// 是否生成C#
        /// </summary>
        public static bool GenerateCSharp
        {
            get
            {
                return mOutOptionIndex == 4 ? true : mGenerateCSharp; //Bytes需要先生成CSharp
            }
            set { mGenerateCSharp = value; }
        }

        /// <summary>
        /// 编码格式索引
        /// </summary>
        private static int mEncodingIndex;

        /// <summary>
        /// 编码格式
        /// </summary>
        private static string[] mEncodingArray = new string[] {"UTF-8", "GB2312"};

        /// <summary>
        /// 当前选中的编码格式
        /// </summary>
        private static Encoding mCurEncoding
        {
            get { return Encoding.GetEncoding(mEncodingArray[mEncodingIndex]); }
        }

        /// <summary>
        /// 输出格式索引
        /// </summary>
        private static int mOutOptionIndex;

        /// <summary>
        /// 输出格式
        /// </summary>
        private static string[] mOutOptionArray = new string[] {"Csv", "Xml", "Json", "Lua", "Bytes"};

        /// <summary>
        /// 当前选中的输出格式
        /// </summary>
        private static string mCurOutOption
        {
            get { return "." + mOutOptionArray[mOutOptionIndex].ToLower(); }
        }

        [MenuItem(MenuPath.SCHEME_MENU_PATH, false, 6)]
        private static void MenuClick()
        {
            Init();
            LoadExcel();
            mWnd.Show();
        }

        private void OnGUI()
        {
            DrawOptions();
            DrawExport();
        }

        private void OnSelectionChange()
        {
            mWnd.Show();
            LoadExcel();
            mWnd.Repaint();
        }

        private static void Init()
        {
            mWnd = GetWindow<SchemeToolsEditor>("配置表工具");
            mRootPath = Application.dataPath;
            mRootPath = mRootPath.Substring(0, mRootPath.LastIndexOf("/"));
            //mRootPath = "E:/Work/Gitee/HTFW";
            mScrollPos = new Vector2(mWnd.position.x, mWnd.position.y - 30);
            mExcelPathList = new List<string>();
        }

        /// <summary>
        /// 绘制配置
        /// </summary>
        private void DrawOptions()
        {
            GUILayout.Label(" 设置", new GUIStyle
            {
                fontSize = 16,
                fontStyle = FontStyle.Bold,
            });
            GUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("输出格式类型:", GUILayout.Width(85));
            mOutOptionIndex = EditorGUILayout.Popup(mOutOptionIndex, mOutOptionArray, GUILayout.Width(125));
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("编码类型:", GUILayout.Width(85));
            mEncodingIndex = EditorGUILayout.Popup(mEncodingIndex, mEncodingArray, GUILayout.Width(125));
            GUILayout.EndHorizontal();
        }

        /// <summary>
        /// 绘制转换
        /// </summary>
        private void DrawExport()
        {
            if (mExcelPathList == null) return;
            GUILayout.Label(" 转换", new GUIStyle
            {
                fontSize = 16,
                fontStyle = FontStyle.Bold,
            });
            if (mExcelPathList.Count < 1)
            {
                EditorGUILayout.LabelField("没有Excel文件被选中!");
                return;
            }

            EditorGUILayout.LabelField($"下列 Excel 将被转换为 {mOutOptionArray[mOutOptionIndex]} ：");
            GUILayout.BeginVertical();
            GenerateCSharp = GUILayout.Toggle(GenerateCSharp, "生成CSharp");
            mScrollPos = GUILayout.BeginScrollView(mScrollPos, false, true, GUILayout.Height(300));
            foreach (string excelPath in mExcelPathList)
            {
                GUILayout.BeginHorizontal();
                GUILayout.Toggle(true, excelPath);
                GUILayout.EndHorizontal();
            }

            GUILayout.EndScrollView();
            GUILayout.EndVertical();
            //转换
            if (GUILayout.Button("确定"))
            {
                if (mGenerateCSharp) Generate();
                Convert();
            }
        }

        /// <summary>
        /// 加载Excel，读取Excel文件路径
        /// </summary>
        private static void LoadExcel()
        {
            if (mExcelPathList == null)
                mExcelPathList = new List<string>();
            mExcelPathList.Clear();
            //获取选中的对象
            UnityEngine.Object[] selectionArray = Selection.objects;
            //判断是否有对象被选中
            if (selectionArray == null || selectionArray.Length == 0)
                return;
            HashSet<string> hashSet = new HashSet<string>(); //过滤重复文件路径
            //遍历每一个对象判断不是Excel文件
            foreach (UnityEngine.Object obj in selectionArray)
            {
                string objPath = AssetDatabase.GetAssetPath(obj);
                if (RuntimeUtil.IsFolder(objPath))
                {
                    List<string> itemPathLst = RuntimeUtil.GetFilesInFolder(objPath);
                    for (int i = 0; i < itemPathLst.Count; i++)
                    {
                        itemPathLst[i] = itemPathLst[i].Replace('\\', '/').Replace(mRootPath + "/", string.Empty);
                        hashSet.Add(itemPathLst[i]);
                    }
                }
                else
                {
                    hashSet.Add(objPath);
                }
            }

            mExcelPathList = RuntimeUtil.FilterFileListBySuffix(hashSet, ".xlsx");
        }

        /// <summary>
        /// 转换Excel文件
        /// </summary>
        private static void Convert()
        {
            for (int i = 0; i < mExcelPathList.Count; i++)
            {
                string excelPath = mRootPath + "/" + mExcelPathList[i];
                EditorUtility.DisplayProgressBar($"Excel To {mOutOptionArray[mOutOptionIndex]}", $"正在转换：{excelPath}",
                    1.0f * (i + 1) / mExcelPathList.Count);
                ExcelHandler handler = ExcelKits.Create(excelPath);

                string fileName = RuntimeUtil.GetFileName(excelPath, GetExtensionStr(SchemeOption.Excel));
                string outPath = GetOutPath(fileName, Index2Option(mOutOptionIndex));
                switch (mOutOptionIndex)
                {
                    case 0:
                        handler.ToCsv(outPath, mCurEncoding);
                        break;
                    case 1:
                        handler.ToXml(outPath, mCurEncoding);
                        break;
                    case 2:
                        handler.ToJson(outPath, mCurEncoding);
                        break;
                    case 3:
                        handler.ToLua(outPath, mCurEncoding);
                        break;
                    case 4:
                        //handler.ToBinary(outPath);
                        EditorUtil.SubscribeCompileFinishedCallBack("ConvertAfterCompile", SchemeDefine.NAME_SPACE,
                            "SchemeToolsEditor");
                        EditorUtility.ClearProgressBar();
                        AssetDatabase.Refresh();
                        mWnd.Close();
                        return;
                }
            }

            EditorUtility.ClearProgressBar();
            AssetDatabase.Refresh();
            Debug.Log($"成功转换 {mExcelPathList.Count} 个 Excel 为 {mOutOptionArray[mOutOptionIndex]}");
            mWnd.Close();
        }

        /// <summary>
        /// Excel 转换为指定类型的配置表
        /// </summary>
        /// <param name="option"></param>
        /// <param name="excelPath">excel全路径</param>
        /// <param name="outPath">输出文件全路径</param>
        public static void Convert(SchemeOption option, string excelPath, string outPath)
        {
            ExcelHandler handler = ExcelKits.Create(excelPath);
            Encoding encoding = Encoding.UTF8;
            switch (option)
            {
                case SchemeOption.Csv:
                    handler.ToCsv(outPath, encoding);
                    break;
                case SchemeOption.Xml:
                    handler.ToXml(outPath, encoding);
                    break;
                case SchemeOption.Json:
                    handler.ToJson(outPath, encoding);
                    break;
                case SchemeOption.Lua:
                    handler.ToLua(outPath, encoding);
                    break;
                case SchemeOption.Bytes:
                    handler.ToBinary(outPath);
                    return;
            }
        }

        public static void ConvertAfterCompile()
        {
            Init();
            LoadExcel();
            mWnd.Show();
            for (int i = 0; i < mExcelPathList.Count; i++)
            {
                string excelPath = mRootPath + "/" + mExcelPathList[i];
                EditorUtility.DisplayProgressBar($"Excel To Binary", $"正在转换：{excelPath}",
                    1.0f * (i + 1) / mExcelPathList.Count);
                ExcelHandler handler = ExcelKits.Create(excelPath);

                string fileName = RuntimeUtil.GetFileName(excelPath, GetExtensionStr(SchemeOption.Excel));
                string outPath = GetOutPath(fileName, SchemeOption.Bytes);
                handler.ToBinary(outPath);
            }

            EditorUtility.ClearProgressBar();
            AssetDatabase.Refresh();
            Debug.Log($"成功转换 {mExcelPathList.Count} 个 Excel 为 Binary");
            mWnd.Close();
        }

        /// <summary>
        /// 生成 CSharp
        /// </summary>
        private static void Generate()
        {
            ScriptTemplateMgr.Disable = true;
            for (int i = 0; i < mExcelPathList.Count; i++)
            {
                string excelPath = mRootPath + "/" + mExcelPathList[i];
                EditorUtility.DisplayProgressBar($"Excel To CSharp", $"正在转换：{excelPath}",
                    1.0f * (i + 1) / mExcelPathList.Count);
                ExcelHandler handler = ExcelKits.Create(excelPath);

                string fileName = RuntimeUtil.GetFileName(excelPath, GetExtensionStr(SchemeOption.Excel));
                string outPath = GetOutPath(fileName, SchemeOption.CSharp);
                handler.ToCSharp(outPath, mCurEncoding);
            }

            EditorUtility.ClearProgressBar();
            AssetDatabase.Refresh();
            ScriptTemplateMgr.Disable = false;
            Debug.Log($"成功生成 {mExcelPathList.Count} 个 CSharp");
        }

        /// <summary>
        /// 将 outOptionIndex 转换为 SchemeOption
        /// </summary>
        /// <param name="outOptionIndex"></param>
        /// <returns></returns>
        static SchemeOption Index2Option(int outOptionIndex)
        {
            switch (outOptionIndex)
            {
                case 0:
                    return SchemeOption.Csv;
                case 1:
                    return SchemeOption.Xml;
                case 2:
                    return SchemeOption.Json;
                case 3:
                    return SchemeOption.Lua;
                case 4:
                    return SchemeOption.Bytes;
                default:
                    return SchemeOption.None;
            }
        }

        /// <summary>
        /// 获取输出路径
        /// </summary>
        /// <param name="name"></param>
        /// <param name="schemeOption"></param>
        /// <returns></returns>
        private static string GetOutPath(string name, SchemeOption schemeOption)
        {
            return $"{GetOutFolder(schemeOption)}{name}{GetExtensionStr(schemeOption)}";
        }

        /// <summary>
        /// 获取输出文件夹路径
        /// </summary>
        /// <param name="schemeOption"></param>
        /// <returns></returns>
        private static string GetOutFolder(SchemeOption schemeOption)
        {
            string folderStr;
            switch (schemeOption)
            {
                case SchemeOption.Excel:
                    folderStr = SchemeDefine.ExcelFolderPath;
                    break;
                case SchemeOption.Csv:
                    folderStr = SchemeDefine.CsvFolderPath;
                    break;
                case SchemeOption.Xml:
                    folderStr = SchemeDefine.XmlFolderPath;
                    break;
                case SchemeOption.Json:
                    folderStr = SchemeDefine.JsonFolderPath;
                    break;
                case SchemeOption.Lua:
                    folderStr = SchemeDefine.LuaFolderPath;
                    break;
                case SchemeOption.Bytes:
                    folderStr = SchemeDefine.BinaryFolderPath;
                    break;
                case SchemeOption.CSharp:
                    folderStr = SchemeDefine.CSharpFolderPath;
                    break;
                default:
                    folderStr = string.Empty;
                    break;
            }

            if (folderStr.Equals(string.Empty) == false)
                RuntimeUtil.CheckOrCreateFolder(folderStr);

            return folderStr;
        }

        /// <summary>
        /// 获取文件扩展名
        /// </summary>
        /// <param name="schemeOption"></param>
        /// <returns></returns>
        private static string GetExtensionStr(SchemeOption schemeOption)
        {
            switch (schemeOption)
            {
                case SchemeOption.Excel:
                    return ".xlsx";
                case SchemeOption.Csv:
                    return ".csv";
                case SchemeOption.Xml:
                    return ".xml";
                case SchemeOption.Json:
                    return ".json";
                case SchemeOption.Lua:
                    return ".lua";
                case SchemeOption.Bytes:
                    return ".bytes";
                case SchemeOption.CSharp:
                    return ".cs";
                default:
                    return string.Empty;
            }
        }
    }
}